﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Pokemon
{
    /// <summary>
    /// Blank be used to caries any DrawableGameComponent object
    /// </summary>
    public class Blank:DrawableGameComponent
    {

        #region Attribute

        protected Vector2 _size;

        /// <summary>
        /// chi ra vi tri that cua o blank tren man hinh
        /// </summary>
        protected Vector2 _position;

        private readonly List<DrawableGameComponent> _components = new List<DrawableGameComponent>();

        private List<DrawableGameComponent> _removeableComponents = new List<DrawableGameComponent>();

        private List<DrawableGameComponent> _addComponents = new List<DrawableGameComponent>(); 

        protected Pokemon _pokemon;        

        protected Grid _owner;

        protected List<DrawableGameComponent> _updatedComponents = new List<DrawableGameComponent>();

#endregion

        public Blank(Game game, Vector2 pos, Vector2 size, Grid owner) 
            : base(game)
        {
            Position = pos;
            _size = size;
            _owner = owner;
            ZombieMoveOut += ZombieMoveToNextBlank;
            InitEvent();            
        }

        #region Properties

        public Vector2 Size
        {
            get { return _size; }
            set { _size = value; }
        }

        public Vector2 Position
        {
            get { return _position; }
            set { _position = value; }
        }

        public Grid Owner
        {
            get { return _owner; }
            set { _owner = value; }
        }

        public Pokemon Pokemon
        {
            get { return _pokemon; }
            set { _pokemon = value; }
        }

        public List<DrawableGameComponent> Components
        {
            get { return _components; }
        }

        #endregion

        #region Add, Remove, Move Component

        /// <summary>
        /// Add new object in blank
        /// </summary>
        /// <param name="item"></param>
        public void Add(DrawableGameComponent item)
        {
            _addComponents.Add(item);
            //_components.Add(item);
            if (item is Unit)
                ((Unit) item).Owner = this;
        }

        /// <summary>
        /// Remove object in blank
        /// </summary>
        /// <param name="item"></param>
        public void Remove(DrawableGameComponent item)
        {
            _removeableComponents.Add(item);
        }

        /// <summary>
        /// Move object to another blank
        /// </summary>
        /// <param name="item"></param>
        /// <param name="blank"></param>
        public void Move(DrawableGameComponent item, Blank blank)
        {
            _components.Remove(item);
            blank.Add(item);
        }

#endregion

        #region Event: Raise when use click on the blank

        public delegate void Click(object sender, Point p);

        public event Click Clicked;

        public void OnClicked(Point p)
        {
            Click handler = Clicked;
            if (handler != null) handler(this, p);
        }

        public void BlankMainGridOnClicked(object sender, Point p)
        {
            //if no Pokemon in this blank and user choose one card in panelButton, create it
            PushalbeBlank blank = ((GameplayScreen)_owner.Owner).GetPanelGridPushBlank();
            if (_pokemon == null && blank != null)
            {
                string cardName = blank.GetCardName();

                switch (cardName)
                {
                    case "Pikachu":
                        _pokemon = new Pikachu(_owner.Owner.CurrGame, this,
                                                new Vector2(p.X, p.Y)
                                                );
                        break;
                    case "Blaziken":
                        _pokemon = new Blaziken(_owner.Owner.CurrGame, this,
                                                new Vector2(p.X, p.Y)
                                                );
                        break;
                    case "Charizard":
                        _pokemon = new Charizard(_owner.Owner.CurrGame, this,
                                                new Vector2(p.X, p.Y));
                        break;
                    case "Blastoise":
                        _pokemon = new Blastoise(_owner.Owner.CurrGame, this,
                                                new Vector2(p.X, p.Y));
                        break;
                    case "Venusaur":
                        _pokemon = new Venusaur(_owner.Owner.CurrGame, this,
                                                new Vector2(p.X, p.Y));
                        break;
                    case "Dragonite":
                        _pokemon = new Dragonite(_owner.Owner.CurrGame, this,
                                                new Vector2(p.X, p.Y));
                        break;
                    case "Mushroom":
                        _pokemon = new Mushroom(Game, this, new Vector2(p.X, p.Y));
                        break;
                    case "Boom":
                        BoomItem b = new BoomItem(_owner.Owner.CurrGame, @"Content/Items/PlayingItems/Boom/BoomDef.xml", 
                            this, new Vector2(p.X, p.Y));
                        LayerManager layer = Game.Services.GetService(typeof (LayerManager)) as LayerManager;
                        layer.Add(b, 7);
                        //_components.Add(b);
                        break;                    
                }
                ((GameplayScreen)_owner.Owner).OnPokemonDowned();

                if (_pokemon == null) return;

                _pokemon.Initialize();

                _pokemon.NormalizePosition();

                _components.Add(_pokemon);                
            }            
                
            //double minDistance = Math.Sqrt(Size.X * Size.X)
        }

        public void InitEvent()
        {
            Clicked += BlankMainGridOnClicked;
        }

        public void RemoveEvent()
        {
            Clicked -= BlankMainGridOnClicked;
        }

        /// <summary>
        /// Add func to process event Click
        /// </summary>
        /// <param name="func">Pointer to func</param>
        public void AddFunc(Click func)
        {
            Clicked += func;
        }

        /// <summary>
        /// Remove func to process event Click
        /// </summary>
        /// <param name="func"></param>
        public void RemoveFunc(Click func)
        {
            Clicked -= func;
        }

#endregion

        #region Event: Raise when Zombie move out on the blank

        public delegate void MoveOut(Zombie zombie);

        private event MoveOut ZombieMoveOut;

        public void OnZombieMoveOut(Zombie zombie)
        {
            MoveOut handler = ZombieMoveOut;
            if (handler != null) handler(zombie);
        }

        private void ZombieMoveToNextBlank(Zombie zombie)
        {            
            _updatedComponents.Add(zombie);
        }

        #endregion

        public static double GetDistance(Point p1, Point p2)
        {
            return Math.Sqrt(Math.Pow(p1.X - p2.X, 2) + Math.Pow(p1.Y - p2.Y, 2));
        }

        public Zombie GetZombieNearest(Point p1)
        {
            Zombie z = null;
            Point minPoint = new Point((int)(Position.X + Size.X), (int)(Position.Y + Size.Y));
            double minDis = GetDistance(p1, minPoint);
            foreach (var drawableGameComponent in _components)
            {
                if (drawableGameComponent is Zombie)
                {
                    Zombie t = (Zombie) drawableGameComponent;
                    var dis = GetDistance(p1, t.GetCenterPoint());
                    if (dis < minDis)
                    {
                        minDis = dis;
                        z = t;
                    }                        
                }
            }
            return z;
        }

        #region Draw & Update

        public override void Draw(GameTime gameTime)
        {           
            foreach (var drawableGameComponent in _components)
            {
                drawableGameComponent.Draw(gameTime);
            }            
        }

        public override void Update(GameTime gameTime)
        {
            AutoInsertComponent();            
            AutoRemoveComponent();

            foreach (var drawableGameComponent in _components)
            {
                drawableGameComponent.Update(gameTime);
            }

            if (_updatedComponents.Count > 0)
            {
                Blank leftBlank, rightBlank;
                _owner.GetNeighborBlank(this, out leftBlank, out rightBlank);
                if (leftBlank != null)
                {
                    foreach (var drawableGameComponent in _updatedComponents)
                    {
                        Move(drawableGameComponent, leftBlank);
                    }
                }
                else
                   Game.Exit();//return;               
                _updatedComponents.Clear();                
            }

            AutoRemoveComponent();
            AutoInsertComponent();
            
        }

#endregion
        public void AutoRemoveComponent()
        {
            foreach (var drawableGameComponent in _removeableComponents)
            {
                _components.Remove(drawableGameComponent);
                if (drawableGameComponent is Unit)
                    ((Unit)drawableGameComponent).Owner = null;
                if (drawableGameComponent is Pokemon)
                    _pokemon = null;                
            }
            _removeableComponents.Clear();
        }

        public void AutoInsertComponent()
        {
            foreach (var drawableGameComponent in _addComponents)
            {
                _components.Add(drawableGameComponent);                
            }
            _addComponents.Clear();
        }

        public void DrawBorder()
        {
            _owner.Owner.ScreenManager.SpriteBatch.Draw(Game.Content.Load<Texture2D>(@"Textures/Backgrounds/rect"),
                                                        new Rectangle((int)_position.X, (int)_position.Y, (int)_size.X, (int)_size.Y),
                                                        Color.White);
        }

        public bool IsContainZombie()
        {
            return _components.OfType<Zombie>().Any();
        }        

        public Card GetCard()
        {
            foreach (var component in _components)
            {
                if (component is Card)
                    return (component as Card);
            }
            return null;
        }

        public bool IsContainPoint(Point p)
        {
            Rectangle rectangle = new Rectangle((int)_position.X, (int)_position.Y, (int)_size.X, (int)_size.Y);
            return (rectangle.Contains(p));
        }

        #region Event: Raise when Boom explore

        public delegate void BoomExplore(List<DrawableGameComponent>_zombies);

        public event BoomExplore boomExploring;

        public void OnBoomExploring()
        {
            BoomExplore handler = boomExploring;
            if (handler != null)
            {
                List<DrawableGameComponent> list = new List<DrawableGameComponent>();
                foreach (var drawableGameComponent in _components)
                {
                    if (drawableGameComponent is Zombie)
                        list.Add(drawableGameComponent);
                }
                handler(list);
            }
        }

        #endregion
    }
}
